#include "serveur.h"

char *depart="depart";

int        sock_tab    [NCONNS] = { [ 0 ... NCONNS-1 ] = -1 };
pthread_t  pid_tab     [NCONNS] = { [ 0 ... NCONNS-1 ] = -1 };//moyen de pas use ceci
log_client log_clients [NCONNS];

int nsocks = 0;
pthread_mutex_t mutex;



void 
perror_and_exit_whenever(int assertion)
{
  if (assertion)
    {
      perror("appel fonction perror : ");
      exit(EXIT_FAILURE);
    }
}



void *
requete(void * fdc)
{
  int i = (int) fdc;
  printf("je vais get requete\n");

  char *requete = recupere_requete(sock_tab[i]);
  if (requete == NULL)
    {
      deconnecter_client(i);
      return NULL;
    }
  
  
  requete_t req = traiter_requete(requete);
  
  free(requete);
  requete = NULL;

  printf("methode = %d\npath =%s\n",req->methode,req->url);
  
  if (req->methode == 0)
    get_page(sock_tab[i],req->url);
  
  liberer_requete(req);
  deconnecter_client(i);
  return NULL;
}

void
deconnecter_client(int indice)
{
  pthread_mutex_lock(&mutex);
   
  rentrer_log(&log_clients[indice]);
  printf("%s deconnecte\n\n",log_clients[indice].nom);
  close(sock_tab[indice]);

  liberer_log(&log_clients[indice]);
  sock_tab[indice] = -1;
  nsocks--;
  //  pthread_kill(pid du main,usr1);
  pthread_mutex_unlock(&mutex);
}

void
liberer_log(log_client *log)
{
  if(log->ip)
    free(log->ip);

  if (log->nom)
    free(log->nom);
  if (log->date_connexion)
    free(log->date_connexion);
  if (log->requete)
    free(log->requete);
  if (log->code_retour)
    free(log->code_retour);
  if (log->user_agent)
    free(log->user_agent);


  memset(log,0,sizeof(struct log_client));
  
}

void
usage()
{
  fprintf(stderr,"Usage : ./serveur [fonctionnement]\nfonctionnement = thread ou select\n");
  exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
  //TESTER ARGS POUR SAVOIR SI ON UTILISE SELECT OU THREAD §
  if (argc < 2 || (strcmp(argv[1],"thread") != 0 && strcmp (argv[1],"select")))
    usage();


  //open fichier log d'erreurs et rediriger la sortie derreur
  int fderr = open(LOG_ERROR,O_WRONLY | O_CREAT | O_APPEND, 0600);
  if (fderr == -1)
    {
      perror("error log\n");
      exit(1);
    }
  dup2(fderr,2);
  close(fderr);
  


  int sock = socket(AF_INET,SOCK_STREAM,0);
  pthread_mutex_init(&mutex,NULL);
  
  struct sockaddr_in addr;
  socklen_t socklen = sizeof addr;

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof sin);


  
  sin.sin_family = AF_INET;
  sin.sin_port = htons(PORT);

  int b = 1;

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,&b,sizeof(b));


  if (bind(sock, (struct sockaddr*)&sin,sizeof sin) == -1)
    {
      perror("bind problem");
      exit(1);
    }

  if (listen(sock, 1)== -1)
    {
      perror("listen problem");
      exit(1);
    }
  
  
  printf("connecte, bind et listen reussis\n");

  if (strcmp(argv[1],"thread")==0)
    {

      pthread_attr_t thread_attr;

      if (pthread_attr_init (&thread_attr) != 0) {
	fprintf (stderr, "pthread_attr_init error");
	exit (1);
      }

      if (pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
	fprintf (stderr, "pthread_attr_setdetachstate error");
	exit (1);
      }

      while(1)//il faut faire une version avec select
	{      
	  for (int i = 0; i < NCONNS; i++) 

	    {
	      if (sock_tab[i] == -1){//ne pas utiliser sock_tab, juste
		//accept, mais utiliser pause apres
		
		sock_tab[i] = accept(sock,(struct sockaddr*)&addr,&socklen);
		nsocks++;
		
		printf("nouveau client\n");
		//	    printf("nouveau client : %s, %s\n",user[i],serv); //getnameinfo(inet_ntoa(addr.sin_addr)));
	    
		init_log(&addr,&log_clients[i]);
	    
		pthread_create(&pid_tab[i],&thread_attr, requete, (void *)i);
		break;
	      }
	    }

	  //pause ici -> faire sigaction() pour debloquer
	}
    }

  else //select
    {

    }

  close(sock);

  return EXIT_SUCCESS;
}



void
get_page(int isock, char *path)
{
  //CE QUI SUIT : IL FAUT FAIRE LES TESTS DE VALIDITE
  // + METTRE A JOUR LES STRUCTURE DE LOG (reponse requete)

  //char *realpath = 
  printf("coucou1\n");

  if (est_dossier(path))
    {
      printf("coucou2\n");
      if (!index_existe(path))
	{
	  printf("coucou2,5\n");
	  
	  char *path_cpy = strstr(path,ROOT);
	  
	  printf("path cpy = %s\n",path_cpy);
	  char *index =generer_index(path_cpy+strlen(ROOT),"index");
	  
	  printf("coucou2,6\n"); 
	  
	  if (index != NULL)
	    {
	      int r = write(isock,requete_ok,sizeof(char)*strlen(requete_ok) );
	      perror_and_exit_whenever(r <= 0);
	      
	      r = write(isock,content, sizeof(char)*strlen(content));
	      perror_and_exit_whenever(r <= 0);

	      r = write(isock,index,sizeof(char)*(strlen(index)+1));
	      perror_and_exit_whenever(r <= 0);

	      char *c = "\n";
	      r = write(isock,c,sizeof(char)*2);

	  //faire test pour voir si le write sest bien passe
	      free(index);
	      index = NULL;
	    }

	  //passer code erreur ?
	}
      else
	{
	  strcat(path,"index.html");//TESTER SI CEST PAS .HTM
	  int fdindex = open(path,O_RDONLY);
	  copier_fichier(isock,fdindex);
	  close(fdindex);
	}
    }
    
  else //on reclame un fichier
    {
      int fd = open(path,O_RDONLY);
      perror_and_exit_whenever(fd == -1);

      int r = write(isock,requete_ok,sizeof(char)*strlen(requete_ok) );
      perror_and_exit_whenever(r <= 0);
      
      r = write(isock,content, sizeof(char)*strlen(content));
      perror_and_exit_whenever(r <= 0);
      
      copier_fichier(isock,fd);

      close(fd);
	      
    }
  printf("coucou4\n");

}

void
get_head(int isock, char *path)
{
  
}




void 
init_log(struct sockaddr_in* addr,log_client* log)
{
  //initialise qu'une partie des logs, le reste est fait durant le traitement de la requete

  char serv[SERV_SIZE]; 
  char name[BUFFER_SIZE];

  int gn =  getnameinfo((struct sockaddr*)addr, sizeof *addr,
			name, BUFFER_SIZE,
			serv, SERV_SIZE,0);
		
  printf("name = %s\n",name);

  perror_and_exit_whenever(gn != 0);


  time_t t = time(NULL);
  char *date = asctime(localtime(&t));
  char *ip = inet_ntoa(addr->sin_addr);
  
  printf("ici\n");
  printf("log->ip = %s\nip = %s de taille %d",log->ip,ip,strlen(ip));

  log->ip = malloc(sizeof(char)*(strlen(ip)+1));
printf("ici\n");
  log->nom = malloc(sizeof(char)*(strlen(name)+1));
printf("ici\n");
  log->date_connexion = malloc(sizeof(char)*(strlen(date)+1));
  printf("ici\n");

  strcpy(log->ip,ip);
  strcpy(log->nom,name);
  strcpy(log->date_connexion,date);
  printf("ici\n");
  
  /*if (ip)
    {
      free(ip);
      ip= NULL;
    }
  */
}
  

void
rentrer_log(log_client *log)
{
  FILE* log_f = fopen(LOG_FILE,"a");
  perror_and_exit_whenever(!log_f);
  
  fprintf(log_f,"\n%s",log->date_connexion);
  fprintf(log_f,"%s\n",log->ip);
  fprintf(log_f,"%s\n",log->nom);
  fprintf(log_f,"%s\n",log->requete);
  fprintf(log_f,"%s\n",log->code_retour);
  
  fclose(log_f);
  
}


void
copier_fichier(int fd_dst,int fd_src)
{
  char buff_copier[BUFFER_SIZE];
  int r_copier;
  while ((r_copier = read(fd_src,buff_copier,BUFFER_SIZE)) > 0)
    if (write(fd_dst,buff_copier,r_copier) <= 0)
      perror_and_exit_whenever(1);
  

}


